package org.wenhuayuan.uilibrary.tab.top;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;

import org.wenhuayuan.hiapplib.util.HiDisplayUtil;
import org.wenhuayuan.uilibrary.R;
import org.wenhuayuan.uilibrary.tab.common.IHiTabLayout;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class HiTabTopLayout extends HorizontalScrollView implements IHiTabLayout<HiTabTop, HiTabTopInfo<?>> {

    private List<OnTabSelectedListener<HiTabTopInfo<?>>> tabSelectedListeners = new ArrayList<>();
    private List<HiTabTopInfo<?>> infoList; // 底部按钮数据
    private HiTabTopInfo<?> preSelectedInfo;
    private String TAG = "TOP_FRAME_LAYOUT_TAG";

    public HiTabTopLayout(Context context) {
        this(context, null);
    }

    public HiTabTopLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HiTabTopLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.init();
    }

    @Override
    public HiTabTop findTab(@NonNull HiTabTopInfo<?> info) {
//        ViewGroup linearLayout = getRootLayout(false);
        ViewGroup linearLayout = findViewWithTag(TAG);
        for (int i = 0; i < linearLayout.getChildCount(); i ++) {
            View child = linearLayout.getChildAt(i);
            if (child instanceof HiTabTop) {
                HiTabTop tabTop = (HiTabTop)child;
                if(tabTop.getTabInfo() == info) {
                    return tabTop;
                }
            }
        }
        return null;
    }

    @Override
    public void addTabSelectedChangeListener(OnTabSelectedListener<HiTabTopInfo<?>> listener) {
        tabSelectedListeners.add(listener);
    }

    @Override
    public void defaultSelected(@NonNull HiTabTopInfo<?> defaultInfo) {
        selected(defaultInfo);
    }

    @Override
    public void inflateInfo(@NonNull List<HiTabTopInfo<?>> infoList) {
        if (infoList.isEmpty()) return;
        this.infoList = infoList;
        LinearLayout rootView = getRootLayout(true);
        preSelectedInfo = null;
        // 清除已经添加过的HiTabBottom的监听
        // 在使用remove时，会出现一边循环一边删除的问题。解决方式从后向前删或者使用Iterator迭代器遍历
        Iterator<OnTabSelectedListener<HiTabTopInfo<?>>> iterator = tabSelectedListeners.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() instanceof HiTabTop) {
                iterator.remove();
            }
        }
        for (int i = 0; i < infoList.size(); i ++) {
            final HiTabTopInfo<?> info = infoList.get(i);
            HiTabTop tabTop = new HiTabTop(getContext());
            rootView.addView(tabTop);
            tabSelectedListeners.add(tabTop);
            tabTop.setHiTabInfo(info);
            tabTop.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    selected(info);
                    autoScroll(info); // 自动滚动
                }
            });

        }
    }

    int tabWidth = 0; // 单个tab的控件宽度
    int scrollWidth = 0; // scrollView需要滚动的距离
    /**
     * 自动滚动算法
     * @param info
     */
    private void autoScroll(HiTabTopInfo<?> info) {
        HiTabTop tabTop = findTab(info); // 根据info获取对应tab
        if (null == tabTop) return;
        // 获取tab的position
        int index = infoList.indexOf(info);

        // 获取tab在屏幕上的坐标
        int[] location = new int[2];
        tabTop.getLocationInWindow(location);
        Log.i("HiTabTopLayout", "tabTop.getWidth = " + tabTop.getWidth() + "--getMeasuredWidth=" +tabTop.getMeasuredWidth());
        if(tabWidth == 0) {
            tabWidth = tabTop.getWidth();
        }
        // 获取tab位于屏幕的左侧，还是右侧
        boolean isTapRight = (tabWidth / 2 + location[0]) > HiDisplayUtil.getDisplayWidthInPx(getContext()) / 2;
        if (isTapRight) {
            // 当点击处于屏幕的右侧时，向右找2个tab
            scrollWidth = getScrollWidth(index, 2);
        } else {
            // 当点击处于屏幕的左侧时，向左找2个tab
            scrollWidth = getScrollWidth(index, -2);
        }

        scrollTo(getScrollX() + scrollWidth, 0); // 执行滚动
    }

    /**
     * 获取当前可滚动的范围距离
     * @param index tab-position
     * @param range 滚动的范围，向左找，还是向右找
     * @return
     */
    private int getScrollWidth(int index, int range) {
        scrollWidth = 0;
        for (int i = 0; i <= Math.abs(range); i ++) {
            int next;// 保存下一个位置/上一个位置
            if(range < 0) {
                // 点击屏幕的左侧
                next = range + i + index;
            } else {
                // 点击屏幕的右侧
                next = range - i + index;
            }

            if (next >= 0 && next < infoList.size()) {
                if (range < 0) {
                    // 点击屏幕的左侧
                    scrollWidth -= calculateScrollWidth(next, false);
                } else {
                    // 点击屏幕的右侧
                    scrollWidth += calculateScrollWidth(next, true);
                }
            }
        }

        return scrollWidth;
    }

    // View.getLocalVisibleRect(rect); //以目标 View 左上角 为参考系
    // ====== rect.left 屏幕左侧======
    // 以view的左顶点为原点。若左顶点可见，则rect.left恒等于0，rect.right恒等于控件width;
    // 若控件部分可见，即左顶点不可见，右顶点可见。则rect.left等于屏幕左顶点到控件左顶点x轴的距离;[部分可见则left>0]
    // 若左顶点完全不可见，则rect.left也等于屏幕左顶点到控件左顶点x轴的距离; [完全不可见则left<0]
    //
    // ====== rect.right 屏幕右侧======
    // 以view的左顶点为原点。若右顶点可见，即控件完全可见。则rect.right恒等于控件width，rect.left恒等于0;
    // 若控件部分可见，即左顶点可见，右顶点不可见。则rect.right等于右顶点到屏幕x轴的距离;[部分可见则right>0]
    // 若控件完全不可见，则rect.right等于右顶点到屏幕x轴的距离 + 屏幕的宽度;[完全不可见则right>0]
    //
    // View.getGlobalVisibleRect(rect); //以屏幕 左上角 为参考系的
    // ====== rect 屏幕======
    // 以屏幕的左顶点为原点。则rect.left等于View左顶点到屏幕x轴距离，rect.right等于View右顶点到屏幕x轴距离;
    // View左顶点在屏幕左侧不可见，则rect.left<0且rect.left=左侧最后一个部分可见View的rect.right-width + N*width
    // View右顶点在屏幕右侧不可见，则rect.right>0且rect.right=右侧最后一个部分可见View的rect.left + N*width
    //

    /**
     * 计算指定位置控件可以滚动的距离
     * @param index 指定位置控件
     * @param tapRight 是否点击了右侧
     * @return 可以滚动的距离
     */
    private int calculateScrollWidth(int index, boolean tapRight) {
        HiTabTop target = findTab(infoList.get(index));
        if(null == target) return 0;

        Rect rect = new Rect();
        target.getLocalVisibleRect(rect); // 判断是否可见
//        target.getGlobalVisibleRect(rect); // 判断是否可见
        Log.i("HiTabTopLayout", "=====点击了======"+(tapRight?"右侧":"左侧"));
        Log.i("HiTabTopLayout", "被选中tab下标"+index+ "-"+ target.getTabInfo().name + "--" + "tabWidth = " + tabWidth);
        Log.i("HiTabTopLayout", "rect.right = " + rect.right);
        Log.i("HiTabTopLayout", "rect.left = " + rect.left);
        if (tapRight) { // 点击屏幕右侧
            if(rect.right > tabWidth) { // right坐标大于控件的宽度时，说明完全没有显示
                return tabWidth;
            } else { // 部分显示，减去已显示得宽度
                return tabWidth - rect.right;//左顶点可见，右顶点不可见。则rect.right等于右顶点到屏幕x轴的距离
            }
        } else {// 点击屏幕左侧
            if(rect.left <= -tabWidth) { // left坐标小于等于控件得宽度，说明完全没有显示
                return tabWidth; // 完全不可见，则rect.left等于屏幕左顶点到控件左顶点x轴的距离
            } else if(rect.left > 0) { // 显示部分
                return rect.left; // 左顶点不可见，右顶点可见。则rect.left等于屏幕左顶点到控件左顶点x轴的距离;
            }
            return 0;
        }

    }
    private LinearLayout getRootLayout(boolean clear) {
        LinearLayout rootView = (LinearLayout) getChildAt(0);
        if (null == rootView) {
            rootView = new LinearLayout(getContext());
            rootView.setOrientation(LinearLayout.HORIZONTAL);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            addView(rootView, params);
        } else if(clear) {
            rootView.removeAllViews();
        }
        rootView.setTag(TAG); // 为view设置tab，以便获取
        return rootView;
    }

    private void init() {
        setVerticalScrollBarEnabled(false);
        setBackgroundColor(getResources().getColor(R.color.color_white));
        setAlpha(0.9f);
    }

    private void selected(@NonNull HiTabTopInfo<?> nextInfo) {
        for (OnTabSelectedListener listener : tabSelectedListeners) {
            // 第一次preSelectedInfo会为null
            listener.onTabSelectedChange(infoList.indexOf(nextInfo), preSelectedInfo, nextInfo);
        }
        this.preSelectedInfo = nextInfo;
    }
}
